<?php

namespace plugin\ai\app\controller;

use Exception;
use Intervention\Image\ImageManagerStatic as Image;
use plugin\ai\app\modelHandler\GptAudio;
use plugin\ai\app\service\Audio;
use plugin\ai\app\service\Common;
use plugin\ai\app\service\User;
use plugin\user\api\Limit;
use support\exception\BusinessException;
use support\Request;
use support\Response;
use Workerman\Connection\AsyncTcpConnection;
use Workerman\Protocols\Http\Chunk;

/**
 * 语音相关接口
 */
class AudioController extends Base
{

    /**
     * 不需要登录的方法
     *
     * @var string[]
     */
    protected $noNeedLogin = ['speech', 'xunfeiIatAuth'];


    /**
     * 朗读
     *
     * @param Request $request
     * @return Response
     * @throws Exception
     */
    public function speech(Request $request): Response
    {
        $input = $request->input('input');
        if (!$input) {
            return \response('400 Bad Request', 400);
        }
        $setting = Audio::getSetting();
        $enabledYingYing = !empty($setting['enable_yingying_tts']);
        $enabledGpt = !empty($setting['enable_gpt_tts']);
        if (!$enabledYingYing && !$enabledGpt) {
            return \response('Not Support TTS', 403);
        }
        $voice = $request->input('voice', 'yingying');
        if ($voice == 'yingying' || !$enabledGpt) {
            return redirect('https://dict.youdao.com/dictvoice?audio='.urlencode($input).'&le=zh');
        }

        // 传了Authorization代表用户使用了自己的apikey则不做余额扣除
        if (!$request->header('Authorization')) {
            if (static::tryReduceBalance('gpt3', $isVip)) {
                return redirect('https://dict.youdao.com/dictvoice?audio='.urlencode('gpt3余额已经用完，无法执行朗读操作').'&le=zh');
            }
        }

        $handler = new GptAudio($request);
        $connection = $request->connection;
        [$schema, $address] = $handler->getApi();
        $con = new AsyncTcpConnection("tcp://$address", ['ssl' => [
            'verify_peer' => false,
        ]]);
        $con->transport = in_array($schema, ['wss', 'https']) ? 'ssl' : 'tcp';
        $httpBuffer = $handler->buildData(['tts-1', $input, $voice]);
        $con->send($httpBuffer);
        $con->onError = function ($con, $code, $msg) use ($connection) {
            echo $code, $msg;
            if ($connection) {
                $connection->send(new Chunk(json_encode(['error' => ['message' => $msg]])));
                $connection->send(new Chunk(''));
            }
        };
        $con->onMessage = function ($con, $buffer) use ($connection) {
            static $headerCompleted = false, $header = '', $bodyLength = 0, $sentLength = false;
            if (!$headerCompleted) {
                $header .= $buffer;
                if (!$position = strpos($header, "\r\n\r\n")) {
                    return;
                }
                if (preg_match("/Content-Length: (\d+)\r\n/i", $header, $match)) {
                    $bodyLength = (int)$match[1];
                }
                if(!$buffer = substr($header, $position + 4)) {
                    return;
                }
                $headerCompleted = true;
                if ($bodyLength) {
                    if ($connection) {
                        $sentLength += strlen($buffer);
                        $connection->send(new Chunk($buffer));
                        if ($sentLength >= $bodyLength) {
                            $connection->send(new Chunk(''));
                        }
                    }
                    return;
                }
            }
            if ($connection) {
                if ($bodyLength) {
                    $sentLength += strlen($buffer);
                    $connection->send(new Chunk($buffer));
                    if ($sentLength >= $bodyLength) {
                        $connection->send(new Chunk(''));
                    }
                } else {
                    $connection->send($buffer, true);
                }
            }
        };
        $con->connect();
        return response(' ')->withHeaders([
            "Content-Type" => "audio/mpeg",
            "Transfer-Encoding" => "chunked",
        ]);
    }

    /**
     * 讯飞听写鉴权
     * @param Request $request
     * @return Response
     * @throws BusinessException
     */
    public function xunfeiIatAuth(Request $request)
    {
        // 频率限制
        $loginUserId = session('user.id') ?: session('user.uid');
        $freeCountPerDay = $loginUserId ? 50 : 20;
        $isVip = $loginUserId && User::isVip($loginUserId);
        $freeCountPerDay = $isVip ? 200 : $freeCountPerDay;
        try {
            if ($loginUserId) {
                Limit::perDay($loginUserId . "-ai-voice-", $freeCountPerDay);
            }
            $ip = request()->getRealIp();
            // 非内网ip时
            if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                Limit::perDay("$ip-ai-voice-", $freeCountPerDay);
            } else {
                $session = $request->session();
                Limit::perDay($session->getId() ."-ai-voice-", $freeCountPerDay);
            }
        } catch (Throwable $e) {
            return $this->json(1, '你语音额度今日已经用完，如需继续使用，请续费');
        }

        $addr = "wss://iat-api.xfyun.cn/v2/iat";
        $setting = Audio::getSetting();

        return $this->json(0, 'ok', [
            'id' => $setting['xunfei_iat_appid'],
            'auth' => Common::xunFeiAuth($setting['xunfei_iat_appid'], $setting['xunfei_iat_apikey'], $setting['xunfei_iat_secret_key'], $addr)
        ]);
    }

}
